<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use App\Chat\Cache\UnreadTalkCache;
use App\CustHub\Mapper\ChCustomerServiceMapper;
use App\CustHub\Model\ChCustomerService;
use App\CustHub\Model\ChCustomerServiceRobot;
use App\CustHub\Model\ChCustomerServiceRoom;
use App\CustHub\Model\ChRobot;
use App\CustHub\Model\ChTalkRecord;
use App\CustHub\Model\ChTalkSession;
use Hyperf\Database\Model\Builder;
use Hyperf\Database\Model\Model;
use Hyperf\DbConnection\Db;
use Mine\Abstracts\AbstractService;
use Mine\Annotation\Transaction;
use Mine\Exception\NormalStatusException;
use Mine\MineModel;
use function Hyperf\Collection\collect;
use function Hyperf\Collection\data_get;


class ChCustomerServiceService extends AbstractService
{
    public $mapper;

    public function __construct(ChCustomerServiceMapper $mapper)
    {
        $this->mapper = $mapper;
    }

    public function list(array $params)
    {
        $pageSize = $params['page_size'] ?? 10;

        $p = ChCustomerService::query()
            ->select(['id','name','account','online_status','assign_rules','max_sessions','status','created_at'])
            ->withCount(['robots'])
            ->with(['rooms' => function ($query) {
                $query->select(['id','room_name']);
            }])
            ->where('main_uid',$params['main_uid'])
            ->orderByDesc('created_at')
            ->paginate((int)$pageSize);

        $p->getCollection()->transform(function ($item) {
            $assignRules = $item->assign_rules;
            if($assignRules['type'] == 0){
                $item->assign_rules_count = 0;
            }else{
                $item->assign_rules_count = count($item->assign_rules['rule']);
            }
            $item->room_count = $item->rooms->count();
            $item->room_ids = $item->rooms->pluck('id')->toArray();
            $item->addHidden(['assign_rules','rooms']);
            return $item;
        });

        return $this->mapper->setPaginate($p);
    }

    public function save(array $data): mixed
    {
        if($this->mapper->checkAccount($data['account'])){
            throw new NormalStatusException('账号已存在');
        }

        $data['assign_rules'] = [
            'type' => 0,
            'rule' => [
                [
                    'type' => 0,
                    'op' => 0,
                    'value' => 24
                ]
            ]
        ];

        $data['work_time'] = [
            [
                'start_time' => '00:00',
                'end_time' => '23:59'
            ]
        ];

        return $this->mapper->save($data);
    }

    public function detail(array $params): ChCustomerService|Model|string|Builder|null
    {
        $info = $this->mapper->findById($params['id']);

        $robots = $info->robots()->select(['id','nickname','avatar'])->get();

        $info['robot_list'] = $robots;
        $info['robot_ids'] = $robots->pluck('id')->toArray();

        $rooms = $info->rooms()->select(['id','room_name','room_avatar_url'])->get();
        $info['room_list'] = $rooms;
        $info['room_ids'] = $rooms->pluck('id')->toArray();

        $info->addHidden(['uid','main_uid','password','login_ip','login_time','created_at','updated_at']);
        return $info;
    }

    #[Transaction]
    public function update(mixed $id,array $data): bool
    {
        $info = $this->mapper->findById($id);

        if(empty($info)){
            throw new NormalStatusException('客服不存在');
        }


        $jsonFields = ['robot_ids','assign_rules','work_time'];
        foreach ($jsonFields as $field){
            if(isset($data[$field])){
                $data[$field] = json_decode($data[$field],true);
            }
        }
        $rst = $this->mapper->update($id,$data);
        if($rst){
            $existing = $info->robots()->pluck('sort','robot_id')->toArray();
            $robotIds = data_get($data,'robot_ids',[]);
            if(!empty($robotIds)){

                $syncData = [];
                foreach ($data['robot_ids'] as $index => $robotId) {
                    if (isset($existing[$robotId]) && $existing[$robotId] != 0) {
                        // 已存在的，保持原排序
                        $syncData[$robotId] = ['sort' => $existing[$robotId]];
                    } else {
                        // 新增的，排在最后
                        $maxSort = empty($existing) ? 0 : max($existing);
                        $syncData[$robotId] = ['sort' => $maxSort + $index + 1];
                    }
                }

                $syncRst = $info->robots()->sync($syncData);
                if(!empty($syncRst['detached'])){
                    $removeRobotIds = $syncRst['detached'];
                    $this->deleteTalkSession($id,$removeRobotIds);
                }
            }else{
                $info->robots()->detach();
                $existRobotIds = collect($existing)->keys()->toArray();
                if(!empty($existRobotIds)){
                    $this->deleteTalkSession($id,$existRobotIds);
                }
            }
        }
        $this->mapper->clearCache($id);
        return $rst;
    }

    /**
     * 删除会话和聊天记录
     * @param $csId
     * @param $robotIds
     * @return void
     * @throws \Exception
     */
    private function deleteTalkSession($csId,$robotIds): void
    {
        $list = ChTalkSession::query()
            ->where('user_id',$csId)
            ->whereIn('robot_id',$robotIds)
            ->get();

        foreach ($list as $item){
            //删除未读消息缓存
            UnreadTalkCache::getInstance()->reset($csId,$item->robot_id,$item->talk_type, $item->receiver_id);
        }

        ChTalkSession::query()
            ->where('user_id',$csId)
            ->whereIn('robot_id',$robotIds)
            ->delete();

        ChTalkRecord::query()
            ->where('user_id',$csId)
            ->whereIn('robot_id',$robotIds)
            ->delete();
    }

    public function setRooms(array $data): bool
    {
        $info = $this->mapper->findById($data['id']);

        if(empty($info)){
            throw new NormalStatusException('客服不存在');
        }

        $roomIds = data_get($data,'room_ids','');
        $roomIds = json_decode($roomIds,true);
        if(!empty($roomIds)){
            $info->rooms()->sync($roomIds);
        }else{
            $info->rooms()->detach();
        }
        return  true;
    }

    #[Transaction]
    public function delete(array $ids): bool
    {
        $this->mapper->delete($ids);
        ChCustomerServiceRobot::query()
            ->whereIn('customer_service_id',$ids)
            ->delete();
        ChCustomerServiceRoom::query()
            ->whereIn('customer_service_id',$ids)
            ->delete();
        return true;
    }

    /**
     * 修改客服在线状态
     * @param mixed $id
     * @param int $status
     * @return void
     */
    public function changeOnlineStatus(mixed $id,int $status): void
    {
        $this->mapper->update($id,['online_status'=>$status]);
        $this->mapper->clearCache($id);
    }

    /**
     * 发送客服消息
     */
    public function sendMessage(ChRobot $robot,array $data)
    {
        //根据机器人ID获取客服ID
        $robotId = $robot->id;
        $customerService = ChCustomerServiceRobot::query()
            ->whereHas('robots',function ($query) use ($robotId){
                $query->where('id',$robotId);
            })
            ->get();
        //判断是否已达到客服会话数上限

        //发送消息
    }

    public function getCustomerServiceList(array $params)
    {
        $pageSize = (int)$params['page_size'] ?? MineModel::PAGE_SIZE;
        $query = $this->mapper->model::query()
            ->where('uid', $params['uid'])
            ->when(!empty($params['nickname']), function ($query) use ($params) {
                $query->where('nickname', 'like', '%' . $params['nickname'] . '%');
            })
            ->paginate($pageSize);
        return $this->mapper->setPaginate($query);
    }

    public function saveCustomerService(array $params)
    {
        $uid = (int)$params['uid'];
        return $this->mapper->save($params);
    }

    public function deleteCustomerService($id)
    {
        $customerService = $this->mapper->model::where('id', $id)->first();
        if (empty($customerService)) {
            return false;
        }
        $this->mapper->model::where('id', $id)->delete();
//        $links = ChCustomerServiceLink::query()->where('uid', $customerService->uid)->get()->toArray();
//        foreach ($links as $link) {
//            $customerServiceIds = $link['customer_service_ids'] ?? [];
//            $index = array_search($id, $customerServiceIds);
//            if ($index!== false) {
//                // 若找到该 id，则从数组中移除
//                unset($customerServiceIds[$index]);
//                // 重新索引数组
//                $customerServiceIds = array_values($customerServiceIds);
//
//                // 更新数据库中的 customer_service_ids 字段
//                ChCustomerServiceLink::where('id', $link['id'])
//                    ->update(['customer_service_ids' => json_encode($customerServiceIds)]);
//            }
//        }
        return true;
    }

    public function getRobotList(array $params): array
    {
        $info = ChCustomerService::query()
            ->where('id',$params['uid'])
            ->first();
        if(empty($info)){
            throw new NormalStatusException("请选择客服~");
        }

        $pageSize = (int)$params['page_size'] ?? MineModel::PAGE_SIZE;

        $robotList = $info->robots()->orderByRaw('sort asc,id desc')->paginate($pageSize);

        $items = $robotList->items();

        $robotIds = collect($items)->pluck('id')->toArray();
        $uid = $params['uid'];
        $robotMap = UnreadTalkCache::getInstance()->getRobotUnreadNum($uid,$robotIds);
        $robotList->getCollection()->transform(function ($item) use ($robotMap) {
            return [
                'id' => $item['id'],
                'receiver_id' => $item['user_id'],
                'nickname' => $item['nickname'],
                'avatar' => $item['avatar'],
                'corp_name' => $item['corp_name'],
                'login_status' => $item['login_status'],
                'unread_num' => $robotMap[$item['id']] ?? 0,
            ];
        });

        return  $this->mapper->setPaginate($robotList);
    }

    public function getRobotListByType(array $params)
    {
        $csId = $params['cs_id'] ?? '';
        $type = $params['type'] ?? 0;
        $robotId = $params['robot_id'] ?? '';
        $p = Db::table('ch_talk_session as a')
            ->selectRaw('b.id,b.nickname,b.avatar,b.corp_name,b.user_id,b.login_status')
            ->join('ch_robot as b','b.id','=','a.robot_id')
            ->where('a.main_uid',$params['main_uid'])
            ->where('a.talk_type',1)
            ->when($csId,function ($query) use ($csId){
                $query->where('a.user_id',$csId);
            })
            ->when($robotId,function ($query) use ($robotId){
                $query->where('a.robot_id',$robotId);
            })
            ->where(function ($query) use ($type){
                if($type == 1){
                    $query->where('a.is_blocked',1);
                }else{
                    $query->where('a.is_hidden',1);
                }
            })
            ->groupBy('b.id')
            ->paginate((int)$params['page_size']);

        return $this->mapper->setPaginate($p);
    }

    public function getContactList(array $params)
    {
        $robotId = $params['robot_id'];
        $type = $params['type'] ?? 0;
        $keyword = $params['keyword'] ?? '';
        $status = $params['status'] ?? '';
        $p = Db::table('ch_talk_session as a')
            ->selectRaw('a.id,b.nickname,b.avatar,a.is_blocked,a.is_hidden,b.corp_short_name,b.user_id,a.updated_at')
            ->join('ch_contact as b',function ($query) use ($robotId){
                $query->on('b.user_id','=','a.receiver_id')
                    ->where('b.robot_id',$robotId);
            })
            ->where('a.main_uid',$params['main_uid'])
            ->where('a.robot_id',$robotId)
            ->where(function ($query) use ($type){
                if($type == 1){
                    $query->where('a.is_blocked',1);
                }else{
                    $query->where('a.is_hidden',1);
                }
            })
            ->when(filled($status),function ($query) use ($type,$status){
                if($type == 1){
                    $query->where('a.is_hidden',$status);
                }else{
                    $query->where('a.is_blocked',$status);
                }
            })
            ->when($keyword,function ($query) use ($keyword){
                $query->where('b.nickname','like','%'.$keyword.'%');
            })
            ->paginate((int)$params['page_size']);

        $p->getCollection()->transform(function ($item) use ($type) {
            if($type == 1){
                $item->status = $item->is_hidden == 1 ? '是' : '否';
            }else{
                $item->status = $item->is_blocked == 1 ? '是' : '否';
            }
            return $item;
        });

        return $this->mapper->setPaginate($p);
    }
}